﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Table;

namespace BlobStroage
{
    public partial class CloudTable : Form
    {
        public CloudTable()
        {
            InitializeComponent();
            SetStorageAccount();
        }

        public Microsoft.WindowsAzure.Storage.CloudStorageAccount storageAccount;
        public Microsoft.WindowsAzure.Storage.Table.CloudTableClient tableClient;
        public Microsoft.WindowsAzure.Storage.Table.CloudTable cloudTable;
        public static String pKey = "PartitionKey";
        public static String rKey = "RowKey";
        public static string _tableName = "personlist";

        /// <summary>
        /// set account
        /// </summary>
        public void SetStorageAccount()
        {
            storageAccount = Microsoft.WindowsAzure.Storage.CloudStorageAccount.Parse(System.Configuration.ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString);
        }

        /// <summary>
        /// create CloudTableClient
        /// </summary>
        public void CreateCloudTableClient()
        {
            tableClient = storageAccount.CreateCloudTableClient();
        }

        /// <summary>
        /// create cloudtable by cloudtableclient
        /// </summary>
        /// <param name="tableName"></param>
        public void CreateCloudTable(String tableName)
        {
            CreateCloudTableClient();
            cloudTable = tableClient.GetTableReference(tableName);
            cloudTable.CreateIfNotExists();
        }

        /// <summary>
        /// insert a entity to cloudtable
        /// </summary>
        /// <param name="per"></param>
        public void InsertSingleEntity(Person per,String tableName)
        {
            CreateCloudTable(tableName);

            TableOperation to = TableOperation.Insert(per);

            cloudTable.Execute(to);
        }

        /// <summary>
        /// insert a batch of entities
        /// all entities in a batch must have the same partitionKey
        /// </summary>
        /// <param name="list"></param>
        public void InsertBatchEntity(List<Person> list ,String tableName)
        {
            CreateCloudTable(tableName);
            TableBatchOperation batch = new TableBatchOperation();
            for (int i = 0; i < list.Count; i++)
            {
                batch.Insert(list[i]);
            }

            cloudTable.ExecuteBatch(batch);
        }

        /// <summary>
        /// get all entities in cloud table
        /// </summary>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public List<Person> GetAllEntity(string tableName)
        {
            List<Person> list = new List<Person>();
            CreateCloudTable(tableName);
            TableQuery<Person> query = new TableQuery<Person>();
            foreach (Person p in cloudTable.ExecuteQuery(query))
            {
                list.Add(p);
            }
            return list;
        }

        /// <summary>
        /// get all entities by PartitionKey
        /// not support fuzzy search
        /// </summary>
        /// <param name="key"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public List<Person> GetEntityByKey(String value, string tableName)
        {
            List<Person> list = new List<Person>();
            CreateCloudTable(tableName);
            TableQuery<Person> query = new TableQuery<Person>().Where(TableQuery.GenerateFilterCondition("Name", QueryComparisons.Equal, value));
            foreach (Person p in cloudTable.ExecuteQuery(query))
            {
                list.Add(p);
            }
            return list;
        }

        /// <summary>
        /// Union query
        /// </summary>
        /// <returns></returns>
        public List<Person> GetEntityByKey(String pKeyVal, String rKeyVal, string tableName)
        {
            List<Person> list = new List<Person>();
            CreateCloudTable(tableName);
            TableQuery<Person> query = new TableQuery<Person>().Where(
                TableQuery.CombineFilters(
                    TableQuery.GenerateFilterCondition(pKey, QueryComparisons.Equal, pKeyVal),
                    TableOperators.Or,
                    TableQuery.GenerateFilterCondition(rKey, QueryComparisons.LessThan, rKeyVal)
                    )
                );
            foreach (Person p in cloudTable.ExecuteQuery(query))
            {
                list.Add(p);
            }
            return list;
        }

        /// <summary>
        /// Retrieve a single entity
        /// </summary>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public Person GetSingleEntity(String tableName,string pkeyVal,string rkeyVal)
        {
            Person per = new Person ();
            CreateCloudTable(tableName);
            TableOperation retrieve = TableOperation.Retrieve<Person>(pkeyVal, rkeyVal);

            TableResult retult = cloudTable.Execute(retrieve);

            if (retult.Result != null)
            {
                per = (Person)retult.Result;
            }
            else
            {
                per = null;
            }
            return per;
        }

        /// <summary>
        /// update an entity by Pkey and Rkey
        /// InsertOrReplace 
        /// if the entity is exist by the pKey and rKey --->update
        /// if the entity is not exist by the pKey and rKey --->create
        /// </summary>
        /// <param name="tableName"></param>
        public void UpdateEntity(String pKeyVal, string rKeyVal, string tableName, Person person)
        {
            Person per = GetSingleEntity(tableName, pKeyVal, rKeyVal);

            per = person;
            per.PartitionKey = pKeyVal;
            per.RowKey = rKeyVal;

            TableOperation update = TableOperation.InsertOrReplace(per);
            cloudTable.Execute(update);
        }

        /// <summary>
        /// Search the entities property ,for example get all the Person.Name from the entities!
        /// the propertyKey must be: typeof(Key) = typeof(entity.property)
        /// it's all in the List
        /// </summary>
        /// <param name="propertyKey"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public List<String> GetSinglePropertyFromEntities(string propertyKey,string tableName)
        {
            List<String> list = new List<string>();
            CreateCloudTable(tableName);
            TableQuery<DynamicTableEntity> query = new TableQuery<DynamicTableEntity>().Select(new String[] { propertyKey });

            EntityResolver<string> resolver = (pk, rk, ts, props, etag) => props.ContainsKey(propertyKey) ? props[propertyKey].StringValue : null;

            foreach (string _name in cloudTable.ExecuteQuery(query, resolver, null, null))
            {
                list.Add(_name);
            }
            return list;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Person p = new Person() { Name = "x1", Age = 22, Sex = "男", Address = "北京" };
            p.PartitionKey = "xxxxxxx";
            p.RowKey = "yyyyyyy";
            InsertSingleEntity(p, _tableName);
        }

        private void button2_Click(object sender, EventArgs e) 
        {
            List<Person> list = new List<Person>();
            for (int i = 1; i < 6; i++)
            {
                Person p = new Person() { Name = "x-" + i, Age = 20 + i, Sex = "男-" + i, Address = "北京-" + i };
                
                p.PartitionKey = "x";
                p.RowKey = "y-" + i;
                list.Add(p);
            }

            InsertBatchEntity(list, _tableName);
        }

        private void button4_Click(object sender, EventArgs e)
        {
            List<Person> list = GetAllEntity(_tableName);
            foreach (Person p in list)
            {
                listBox1.Items.Add(p.Name);
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            List<Person> list = GetEntityByKey(textBox1.Text, _tableName);
            foreach (Person p in list)
            {
                listBox2.Items.Add(p.Name);
            }
        }

        private void button5_Click(object sender, EventArgs e)
        {
            List<Person> list = GetEntityByKey(textBox2.Text, textBox2.Text, _tableName);
            foreach (Person p in list)
            {
                listBox3.Items.Add(p.Name);
            }
        }

        private void button6_Click(object sender, EventArgs e)
        {
            Person p = GetSingleEntity(_tableName, textBox5.Text, textBox6.Text);
            if (p == null)
            {
                textBox4.Text = "can not find it";
            }
            else
            {
                textBox4.Text = p.Name;
            }
        }

        private void button7_Click(object sender, EventArgs e)
        {
            Person person = new Person();
            person.Name = textBox10.Text;
            person.Age = Convert.ToInt32(textBox9.Text);
            UpdateEntity(textBox8.Text, textBox7.Text, _tableName, person);
        }

        private void button8_Click(object sender, EventArgs e)
        {
            List<String> list = GetSinglePropertyFromEntities(textBox11.Text, _tableName);
            textBox12.Text = list.Count.ToString();
        }

        private void button9_Click(object sender, EventArgs e)
        {
            Person per = GetSingleEntity(_tableName, textBox14.Text, textBox13.Text);
            TableOperation to = TableOperation.Delete(per);
            cloudTable.Execute(to);
        }

        private void button10_Click(object sender, EventArgs e)
        {
            CreateCloudTable(_tableName);
            cloudTable.DeleteIfExists();
        }
    }
}
